package com.lvyuanj.core.ai.controller;


import com.pgvector.PGvector;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.embedding.EmbeddingRequest;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.OpenAiEmbeddingClient;
import org.springframework.ai.openai.OpenAiEmbeddingOptions;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@RestController
@RequestMapping("open-ai")
class OpenAiController {

	@Resource
	private OpenAiChatClient openAiChatClient;

	@Resource
	private OpenAiEmbeddingClient openAiEmbeddingClient;

	@Resource
	private JdbcTemplate jdbcTemplate;

	/**
	 * 调用OpenAI的接口-默认参数
	 * @param msg
	 * @return
	 */
	@GetMapping("/chat")
	public String completion(@RequestParam("msg") String msg) {
		return openAiChatClient.call(msg);
	}

	/**
	 * 调用OpenAI的接口-默认参数
	 * @param msg-输入的文本
	 * @return
	 */
	@RequestMapping(value = "/chat2")
	public Object chat2(@RequestParam(value = "msg") String msg) {
		ChatResponse chatResponse = openAiChatClient.call(new Prompt(msg));
		return chatResponse.getResult().getOutput().getContent();
	}

	/**
	 * 调用OpenAI的接口-自定义参数
	 * @param msg-输入的文本
	 * @return
	 */
	@RequestMapping(value = "/chat3")
	public Object chat3(@RequestParam(value = "msg") String msg) {
		//可选参数在配置文件中配置了，在代码中也配置了，那么以代码的配置为准，也就是代码的配置会覆盖掉配置文件中的配置
		ChatResponse chatResponse = openAiChatClient.call(new Prompt(msg, OpenAiChatOptions.builder()
				//.withModel("gpt-4-32k") //gpt的版本，32k是参数量
				.withTemperature(0.4F) //温度越高，回答得比较有创新性，但是准确率会下降，温度越低，回答的准确率会更好
				.build()));
		return chatResponse.getResult().getOutput().getContent();
	}


	/**
	 * 调用OpenAI的接口-流式接口
	 * @param msg-输入的文本
	 * @return
	 */
	@RequestMapping(value = "/chat4")
	public Object chat4(@RequestParam(value = "msg") String msg) {
		//可选参数在配置文件中配置了，在代码中也配置了，那么以代码的配置为准，也就是代码的配置会覆盖掉配置文件中的配置
		Flux<ChatResponse> flux = openAiChatClient.stream(new Prompt(msg, OpenAiChatOptions.builder()
				//.withModel("gpt-4-32k") //gpt的版本，32k是参数量
				.withTemperature(0.4F) //温度越高，回答得比较有创新性，但是准确率会下降，温度越低，回答的准确率会更好
				.build()));

		flux.toStream().forEach(chatResponse -> {
			System.out.println(chatResponse.getResult().getOutput().getContent());
		});
		return flux.collectList(); //数据的序列，一序列的数据，一个一个的数据返回
	}

	@PostMapping("/embedding")
	public void pgQuery(@RequestBody List<String> wordList) {
		EmbeddingRequest embeddingRequest = new EmbeddingRequest(wordList, OpenAiEmbeddingOptions.builder().build());
		EmbeddingResponse response = openAiEmbeddingClient.call(embeddingRequest);
		List<Double> wordVectors = response.getResult().getOutput();
		List<Float> vectors = wordVectors.stream().map(o -> o.floatValue()).collect(Collectors.toList());
		Object[] neighborParams = new Object[] { new PGvector(vectors) };
		List<Map<String, Object>> rows = jdbcTemplate.queryForList("SELECT * FROM modeldata ORDER BY embedding <-> ? LIMIT 5", neighborParams);
		if (Objects.nonNull(rows) && rows.size() > 0) {
			for (Map<String, Object> row : rows) {
				for (Map.Entry<String, Object> entry : row.entrySet()) {
					String key = entry.getKey();
					Object value = entry.getValue();
					System.out.println("key:"+key + ",value:" + value);
				}
			}
		}
	}
}
